package hasthi.actuators.actions;

import static hasthi.common.constants.HasthiConstants.LOGGER_NAME;
import hasthi.actuators.ActionCenter;
import hasthi.actuators.ActionContext;
import hasthi.actuators.ManagementAction;
import hasthi.actuators.SystemActionsScheduler;
import hasthi.common.HasthiException;
import hasthi.common.XmlBeanUtils;
import hasthi.common.HasthiException.FaultCode;
import hasthi.common.constants.WSDMConstants;
import hasthi.common.constants.WSDMConstants.SystemState;
import hasthi.config.ContactProfile;
import hasthi.config.ResourceProfile;
import hasthi.container.MessageContext;
import hasthi.manager.ManagedResourceType;
import hasthi.manager.ManagerContext;
import hasthi.manager.ManagerHeartbeatDocument;
import hasthi.manager.ManagerHeartbeatDocument.ManagerHeartbeat;
import hasthi.metamodel.ChangeBuffer;
import hasthi.metamodel.ChangeEvent;
import hasthi.metamodel.ResourceUtils;
import hasthi.metamodel.ChangeEvent.ChangeType;
import hasthi.metamodel.resource.EditableManagedResource;
import hasthi.metamodel.resource.Host;
import hasthi.metamodel.resource.ManagedResource;
import hasthi.metamodel.resource.ManagedService;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sun.corba.se.pept.transport.ContactInfo;

public class MngActionUtils {
    private static Log log = LogFactory.getLog(LOGGER_NAME);

    public static void setResourceState(ActionContext actionContext,ManagedResource resource,String state){
        try {
            ((EditableManagedResource)resource).setState(SystemState.valueOf(state));
            actionContext.getRuleEngine().objectChanged(resource);
        } catch (HasthiException e) {
           log.error(e);
        }
    }
    
    public static void setResourceState(ActionContext actionContext,ManagedResource resource,SystemState state){
        try {
            ((EditableManagedResource)resource).setState(state);
            actionContext.getRuleEngine().objectChanged(resource);
        } catch (HasthiException e) {
           log.error(e);
        }
    }
    
    public static void removeResource(ActionContext actionContext,ManagedResource resource){
        try {
            actionContext.getRuleEngine().removeObject(resource);
        } catch (HasthiException e) {
            log.error(e);
        }
    }
    
    
    public static class TypeData{
        public TypeData(ManagedResource resource){
            this.implResource = resource;
        }
        public int count = 1;
        public ManagedResource implResource;
    }
    
    
    public static void updateType2ResourceMap(Map map,ManagedService service,boolean added){
        TypeData val = (TypeData)map.get(service.getType());
        if(added){
            if(val == null){
                val = new TypeData(service);
            }else{
                val.count = val.count +1;
                val.implResource = service;
            }
        }else{
            val.count = val.count - 1;
            if(service.equals(val.implResource)){
                val.implResource = null;
            } 
        }
        map.put(service.getType(), val);
    }
    
    
    public static List findAllDependancies(ActionCenter actionContext,List resources){
        //go though the resource profile, and figure out all the dependancies 1) services to restart are services that depends 
        //on this service that need to be restared
        return resources;
    }
    
    public static List findAllDependents(SystemActionsScheduler actionContext,ManagedResource resource){
        //go though the resource profile, and figure out all the dependancies 1) services to restart are services that depends 
        //on this service that need to be restared
        List list = new ArrayList();
        list.add(resource);
        return list;
    }
    
    
    public static void recoverAService(final ActionCenter system,final ManagedService service){
  

    }
    
    
    public static void resurrectWorkflows(ManagedService service,long time){
        
    }
    
    public static void sendNewRequestForMonitoring(ResourceProfile resourceProfile){
        //TODO send a request to lead service/manager requesting to monitor the resource via WSDM proxy
    }
    
    
    public static String[] getFailureRecipientList(ActionContext actionContext){
       ContactProfile contactInfo = actionContext.getSystemConfig().getProfile().getContactDetails();
       if(contactInfo != null){
           return contactInfo.getDowntimeSinkArray();
       }else{
           return new String[]{"hperera@cs.indiana.edu"};
       }
    }
    
    
    public static void handleDCFailuresFromManager(ActionCenter system, Host host) throws HasthiException{
        String value = (String)system.get("OldDCFailedValue");
        if(value == null || value != host.getWANMountHealth()){
            MngActionUtils.sendUpdateToCoordinator(system,host,"WanMountHealth",host.getWANMountHealth());
            system.put("OldDCFailedValue", host.getWANMountHealth());
        }
    }
    
    
    
    public static void sendUpdateToCoordinator(ActionCenter system, 
            ManagedResource resource, String propertyName, String value) throws HasthiException{
        ManagerContext managerContext = system.getActionContext().getManagerContext();
        
        if(managerContext == null){
            throw new HasthiException("This code must run from a Manager",FaultCode.ConfigError);
        }
        
        Map<QName, ManagedResourceType> resourceDiffMap = managerContext.getResourceDiffMap();
        
        synchronized (resourceDiffMap) {
            ManagedResourceType resourceType = resourceDiffMap.get(resource.getQName());
            if (resourceType == null) {
                resourceType = ManagedResourceType.Factory.newInstance();
                resourceDiffMap.put(resource.getQName(), resourceType);
            }
            XmlBeanUtils.addNameValuePair(resourceType, new QName(WSDMConstants.EXTREME_MANAGEMENT_NS, propertyName),
                    value);
            //we have to set the name after setting name value pairs. Xmlbeans thing.
            resourceType.setName(resource.getQName());
        }
    }
    
}
